Pages

Showing posts with label Agent Script. Show all posts
Showing posts with label Agent Script. Show all posts

Saturday, July 25, 2026

lets Built a Multi-Agent Telecom AI Assistant on Salesforce — Then Gave Claude Access to It Too

Lets Built a Multi-Agent Telecom AI Assistant on Salesforce — Then Gave Claude Access to It Too

Most Agentforce demos you see online are a single agent answering FAQ questions. This is a capstone project I built to go further: a team of four coordinated agents that diagnose network outages, explain bills, walk customers through SIM replacement with real identity verification, and — the part I'm most excited to share — can be reached directly from Claude through a Salesforce MCP server. Here's the full build, architecture, and what I learned shipping it.

TL;DR: One customer-facing Orchestrator agent routes conversations to three specialists — Network Diagnostics, Billing & Plan Advisor, and Technical Support — all written in Agent Script, grounded in real Salesforce data, and backed by RAG for device manuals and policy documents. It's deployed two ways: as a live chat widget on an Experience Cloud self-service portal, and as a connector any Claude user can talk to via a Salesforce MCP server. Compliance isn't an afterthought — SIM replacement enforces KYC verification and OTP validation in the script itself, with mandatory human escalation on any failure.

The Business Problem

Telecom support has a shape most industries don't: the same customer conversation can touch a network outage, a confusing bill, and a broken modem in the same five minutes — and somewhere in there they might also need to replace a lost SIM, which means real identity verification, not just a friendly chatbot. A single-purpose bot answers one of those well and shrugs at the rest. The brief behind this capstone was explicit about that: multi-agent orchestration for support, diagnostics, and billing; RAG grounding against device manuals and service policies; omnichannel delivery through an Experience Site; and Agent Script-driven workflows for identity verification, SIM replacement, and number portability — the exact places where a hallucinating agent would be a genuine liability, not just an inconvenience.

Architecture at a Glance

The design keeps one agent owning the whole conversation. Instead of bouncing the customer between bots, the Orchestrator delegates to specialists as tools and keeps the context and the relationship — so a customer can mention a network issue and a billing question in the same thread without repeating themselves.

Architecture diagram showing channels, the orchestrator agent, three specialist subagents, the actions layer, and the Salesforce data layer

Four layers, top to bottom:

  • Channels — the Experience Site chat widget, Claude via MCP, and voice.
  • Orchestrator — a single Agent Script file that greets the customer, verifies identity, classifies intent, and hands off.
  • Specialist subagents — each scoped to one domain, each with its own reasoning instructions and its own action list.
  • Actions and data — Apex invocable actions, Flow actions, and knowledge/RAG retrieval, all sitting on top of standard field-level security so the agent never sees more than the requesting user could.

Meet the Agent Team

Agent Job Guardrails baked in
Orchestrator (Agent Router) Greets the customer, confirms identity, classifies intent, routes to the right specialist, logs every routing decision Never exposes internal object or API names to the customer; never invents an answer instead of pulling real data
Network Diagnostics Checks outages by zip code, walks through device-specific troubleshooting, opens a ticket only after a remediation attempt fails Won't open a duplicate ticket for an outage already being tracked
Billing & Plan Advisor Explains invoices line by line, recommends plans based on real usage history, executes plan changes Only processes a change through the dedicated Flow action, and only after the customer explicitly confirms the new plan and price
Technical Support Device setup, Wi-Fi/modem troubleshooting, broadband installation scheduling, SIM replacement and activation Never bypasses KYC, never skips OTP, caps retries at three attempts, escalates every security failure to a human

The Data Model Behind It

Nothing here is fictional plan copy — every answer the agent gives is grounded in actual records:

Object Purpose
Account (Person Account) Subscriber profile, KYC status, fraud risk flag
Product2 Plan catalog — data limit, price, contract term
Subscription__c The customer's current plan/line
Device__c Registered devices, warranty, firmware version
SIM__c SIM/eSIM status and replacement history
Invoice__c Billing history, payment status, late fees
Case Service tickets, including agent-created diagnostics
OTP_Verification__c Hashed OTP storage for identity checks
Network_Outage__c Outage data keyed by zip code

Inside the Agent Script

This is where the project earns the "engineering," not just "prompting." Here's a trimmed, cleaned-up look at the Orchestrator's router logic:

start_agent agent_router:
  label: "Agent Router"
  description: "Welcome the user and determine the appropriate subagent based on user input"

  reasoning:
    | - Always greet the customer and confirm their identity before discussing
    |   any account-specific detail.
    | - If the user asks about a network_issue -> hand off to Network_Diagnostics_Agent.
    | - If the user asks a billing_question or requests a plan_change ->
    |   hand off to Billing_Plan_Advisor_Agent.
    | - If the user asks about technical_support (device/Wi-Fi/modem) ->
    |   hand off to Technical_Support_Agent.
    | - If the user asks about sim_replacement or number_portability ->
    |   invoke the corresponding subagent.
    | - Never expose internal system names, DMO names, or raw API responses
    |   to the customer.
    | - Never answer from a generic assumption — always answer from real
    |   retrieved data.
    | - Log every routing decision via the Log_Interaction action before closing.

    actions:
      go_to_Network_Diagnostics_Agent: @utils.transition to @subagent.Network_Diagnostics_Agent
      go_to_Billing_Plan_Advisor_Agent: @utils.transition to @subagent.Billing_Plan_Advisor_Agent
      go_to_Technical_Support_Agent: @utils.transition to @subagent.Technical_Support_Agent

Notice the two rules that do the most work: never expose internal system names and never answer from assumption. Those two lines are the difference between a demo and something you'd actually let a paying customer talk to — they force every specialist to ground its answer in a real Apex or Flow action instead of the model's own guess.

Compliance You Can Trust: The SIM Replacement Walkthrough

SIM replacement is the highest-stakes flow in the whole agent — get it wrong and you've handed a stranger someone else's phone number. So it's scripted deterministically, not left to the model's judgment:

Flow diagram of the SIM replacement process: collect details, look up profile, check KYC status, send OTP, validate OTP with a three-attempt limit, then create and activate the new SIM

The rules that make this safe are stated explicitly in the script itself, not just implied by good intentions:

  • Never bypass KYC verification. If KYC_Status__c isn't Verified, processing stops immediately and the case escalates to a human — no exceptions.
  • Never skip OTP validation, and never generate a random OTP and hand it to the customer directly — it's only ever sent to the registered email.
  • Cap retries at three attempts. A fourth failed OTP entry escalates automatically.
  • Every security-related failure escalates. The agent is never the last line of defense on identity.

That's the pattern worth stealing for any regulated workflow you put behind an agent: let the LLM handle the conversation, but let hard-coded logic — not model judgment — own the parts where being wrong actually hurts someone.

Going Live: Two Ways In

1. The Experience Cloud Self-Service Portal

This is the channel real customers use:

  1. Enable Messaging Settings in Setup.
  2. Configure Routing Configuration.
  3. Create a Queue with Messaging Session as a selected object.
  4. Build and publish a site in Experience Builder.
  5. Commit and activate the service agent you want to deploy.
  6. Create a new channel under Messaging Settings.
  7. Create and publish an Embedded Service Deployment.

Once that's live, the chat widget on the portal is the Orchestrator — customers never know how many specialist agents are working behind it.

2. Bringing the Agent to Claude via MCP

This is the part worth a second look, because it's not something most Agentforce tutorials show: the same agent, reachable from Claude through a standard Salesforce MCP server.

  1. In Setup, go to External Client App Manager and create a new external client app (e.g., "Claude Integration").
  2. Enable OAuth settings, and set the callback URL to Claude's standard MCP callback: https://claude.ai/api/mcp/auth_callback.
  3. Grant the OAuth scopes that matter here: Perform requests at any time (refresh_token, offline_access) and Access Salesforce hosted MCP servers (mcp_api).
  4. Under Security, require PKCE for supported authorization flows, and issue JWT-based access tokens for named users.
  5. Copy the Consumer Key and Consumer Secret.
  6. In Claude, go to Settings → Connectors → Add Custom Connector, and paste in the org's MCP URL along with the Client ID and Client Secret.
  7. Set tool permissions to Always allow, start a new chat, and confirm the connector is enabled for that conversation.

From that point on, anyone with the right access can ask Claude a question and have it reach into the same Salesforce org — same data model, same guardrails — through the org's MCP server, instead of only through the chat widget on the portal.

What Building This Taught Me

A few things stood out that don't show up in the Trailhead version of Agentforce:

  • Guardrails belong in the script, not the prompt. "Never bypass KYC" reads like an instruction, but it only works because it's enforced as a deterministic branch, not a polite request to the model.
  • Multi-agent only feels seamless if one agent owns the conversation. The moment you let the customer talk to three separate bots instead of one Orchestrator quietly delegating, the experience falls apart.
  • MCP turns an agent into a platform. Once the Orchestrator is reachable through a standard MCP server, it stops being "a chatbot on our website" and becomes a capability other tools — like Claude — can use directly.

What's Next

Number portability is the next workflow to script the same way SIM replacement was — same compliance shape, different regulatory checks. I'd also like to push Data Cloud further upstream, so the Network Diagnostics subagent is reasoning over live telemetry instead of a periodically-updated outage object.

If you're building something similar — or you've hit the same "guardrails in the script vs. the prompt" question — I'd love to hear how you approached it in the comments.

Agent Script for Developers: Coding Agentforce Agents Like Real Software

 

Agent Script for Developers: Coding Agentforce Agents Like Real Software

Building an agent by clicking through Agentforce Builder works fine until your logic gets specific — "offer free shipping only if the order total is over $100 AND the customer is a loyalty member AND it's not already on backorder." At that point, natural-language instructions to an LLM start to feel like duct tape. Agent Script is Salesforce's answer: a real, readable scripting language purpose-built for agents.

TL;DR: Agent Script is a declarative, human-readable language for defining Agentforce agents — their subagents (formerly called topics), instructions, variables, and actions — as code instead of only as clicks. It blends natural-language reasoning instructions with deterministic if/else logic, lives in a .agent file inside your Salesforce DX project, and is fully supported in VS Code with syntax highlighting and validation. If you've ever wished you could put an agent under version control, this is how.

Why Developers Should Care

Agentforce Builder's canvas view is genuinely good for admins — natural language in, working agent out. But every agent eventually needs the same things any serious codebase needs: predictable branching logic, reusable structure, code review, and a diff you can actually read. Agent Script gives you all of that because, under the hood, every agent you build in Agentforce — whether through chat, canvas, or script — is Agent Script. The Script view just lets you work with it directly instead of through a UI abstraction.

That matters for a very practical reason: it puts agent definitions in your Salesforce DX project, next to your Apex and LWC, where they can be versioned, code-reviewed, and deployed the same way as everything else you ship.

The Building Blocks of a Script File

An Agent Script file is organized into a small number of named blocks. Once you recognize them, most scripts read top to bottom without much translation:

Block What it holds
config Core agent settings — developer_name, agent_label, description, agent_type, and which Salesforce user the agent runs as.
system Agent-wide instructions and required messages like welcome and error.
variables Named state the agent tracks across a conversation, referenced anywhere as @variables.<name>.
subagent A self-contained unit of behavior — its own description, instructions, and available actions. This is where most of the actual logic lives.
start_agent The entry point every conversation begins at; decides which subagent should handle the user's request.
connected_subagent A reference to a different Agentforce agent in your org, so one agent can delegate work to another.

If "subagent" sounds like a rename, it is — Salesforce renamed topics to subagents in April 2026 with no functional change, so don't be surprised if you see both terms depending on which doc or org version you're looking at.

A Worked Example: Order Status, in Script

Let's script a small piece of the same order-status scenario from our last post — but this time controlling when the agent should hand off to a human instead of just answering.

config:
  developer_name: "Order_Support_Agent"
  agent_label: "Order Support Agent"
  agent_type: "AgentforceServiceAgent"
  default_agent_user: "order_support_agent_user@yourorg.com"
  description: "Helps customers check order status and escalates delayed orders to a human agent."

system:
  welcome: "Hi! I can help you check on an order — what's your order number?"
  error: "Something went wrong on my end. Let me connect you with a teammate."

variables:
  order_status: string
  days_delayed: number

subagent order_lookup:
  description: "Looks up an order's status and delivery estimate when the customer provides an order number."

  reasoning:
    instructions:
      "Ask for the order number if it hasn't been provided ->
       If @variables.days_delayed > 3 | Apologize for the delay before sharing status details.
       Otherwise | Share the order status plainly and offer to help with anything else."
    actions:
      - get_order_status
      - transition_to_escalation

  actions:
    get_order_status:
      description: "Calls Apex to retrieve status, delivery estimate, and delay in days for an order number."
      target: apex://OrderStatusAction

subagent escalation:
  description: "Hands off to a human agent when a delay is significant or the customer asks for a person."
  reasoning:
    instructions:
      "If @variables.days_delayed > 7 | Explain that a specialist will follow up and transition immediately.
       Otherwise | Ask one clarifying question before deciding whether to escalate."

A few things worth noticing:

  • The line with -> inside reasoning.instructions is where Agent Script earns its keep. Everything before it can be plain natural language; everything after can be a hard conditional evaluated against a real variable — not something the LLM has to infer from conversation history.
  • get_order_status here points at apex://OrderStatusAction — the exact custom Apex action with @InvocableMethod we built in the previous post. Agent Script doesn't replace Apex actions; it's the orchestration layer that decides when and whether to call them.
  • Variables like days_delayed give the agent reliable memory instead of leaning on the LLM to remember and recompute values mid-conversation.

Three Ways to Write It (All Produce the Same Thing)

Salesforce is intentionally flexible about how you author a script:

  1. Chat with Agentforce and describe what you want ("if the order's more than a week late, hand it straight to a human") — Agentforce converts that into subagents, actions, and instructions for you.
  2. Canvas view — a visual, block-based editor where / inserts logic patterns like if/else and @ inserts references to subagents, actions, or variables.
  3. Script view — write and edit the raw .agent file directly, with the same syntax highlighting and autocomplete you'd expect from any language extension in VS Code.

All three are the same underlying artifact. You can start in canvas view and drop into script view the moment the logic gets too specific for clicking — and back again.

Working in VS Code with Agentforce DX

If you'd rather live in your editor than in Setup, Agentforce DX brings the whole workflow local:

  1. Generate or retrieve an authoring bundle for your agent into your DX project — it lands at force-app/main/default/aiAuthoringBundles/<Agent_API_Name>/<Agent_API_Name>.agent.
  2. Edit the .agent file directly, or open the Agentforce Vibes panel to describe changes in natural language and let it edit the script for you.
  3. Validate the file before you publish — VS Code's AFDX: Validate This Agent command (or the equivalent CLI command) checks that the script compiles and flags syntax errors with their exact location.
  4. Preview the agent from the script file itself to test behavior before publishing it back to your org.

One habit worth building early: validate often, not just before a deploy. Agent Script errors are usually small — a missing colon, a typo in a block name — and they're far easier to fix one at a time than after you've written fifty lines on top of a broken block.

Where This Fits with What You Already Know

If you've spent time in Flow, a lot of this will feel familiar wearing different clothes: subagents are a bit like Flow's screen-by-screen structure, reasoning instructions are your decision logic, and actions are the same invocable Apex, Flow, and prompt-template building blocks Agentforce already supports. The real shift is that it's all expressed as one readable, versionable file instead of a set of linked records you navigate by clicking.

The Bottom Line

Agent Script doesn't replace Agentforce Builder — it's what Agentforce Builder is writing on your behalf every time you build an agent through chat or canvas. Once your agent's logic outgrows what feels safe to leave entirely to LLM interpretation, dropping into Script view (or straight into VS Code with Agentforce DX) gives you the same rigor you already expect from Apex: version control, code review, and behavior you can actually predict.

Have you tried writing Agent Script directly, or are you still building through canvas view? Let me know how it's going in the comments below.